home *** CD-ROM | disk | FTP | other *** search
Text File | 2001-06-23 | 31.5 KB | 1,119 lines |
- // =================================================================================
- // CDNSAction.cp ©1999 Sustainable Softworks All rights reserved.
- // =================================================================================
- // Perform DNS Deferral
- //
- // IPNetRouter does DNS forwarding using the NAT feature when there
- // is no PPP interface or PPP is connected. The NAT module is
- // programmed to translate DNS requests to our local address to
- // the currently configured DNS server, and the IP module forwards
- // them.
- //
- // When PPP is disconnected, the DNS NAT mappings are disabled so
- // this module can receive DNS traffic and perform DNS Deferral.
- // We intercept simple DNS lookup requests and generate an
- // intermediate response at 2 second intervals until PPP comes
- // back on-line (or we time out). The purpose of these intermediate
- // responses is to prevent the clients DNR from timing out while
- // waiting for PPP to connect.
- //
- // We never actually forward a DNS request on behalf of a client,
- // rather, we string the client along with one CNAME after another
- // until the DNS port mappings are back online, then we tell the
- // client to retry the original DNS request, but this time the request
- // is redirected to a real Name Server by the NAT module.
-
- #include "CompileFlags.h"
- #include "CDNSAction.h"
- #include "CDNSConst.h"
- //#include "myDNS.h"
- #include "CResidentIfInfo.h"
- #include "CConnectionData.h"
- #include "CInterfacesData.h"
- #include "CInterfacesAction.h"
- #include "LInternetAddress.h"
- #include "CProxyControl.h"
-
- #include "IPRouterCommon.h"
- #include "MacSupport.h"
- #include "IPSupport.h"
- #include "CLogAction.h"
- #include <UReanimator.h>
- #include <LString.h>
- #include <LPreferencesFile.h>
- #include <UResourceMgr.h>
- #include <LArray.h>
- #include <LComparator.h>
- #include <LArrayIterator.h>
- #include <UMemoryMgr.h>
- #include <UOpenTptSupport.h>
-
- #include "CReceiveUDPThread.h"
- #include "CSendUDPThread.h"
- #include "CTurboUDPEndpoint.h"
-
- #include <OpenTransport.h>
- #include <OpenTptConfig.h>
- #include <OpenTptInternet.h>
- #include <LInternetMapper.h>
- #include <LOpenTptInetMapper.h>
- #include <OpenTptLinks.h>
- //#include <modnames.h> // names of the standard OT modules.
-
- // Globals
- extern CLogAction* gLogAction;
- extern CResidentIfInfo* gResInfo;
- extern CConnectionData* gConnectionData;
- extern CInterfacesData* gInterfacesData;
- extern CInterfacesAction* gInterfacesAction;
- //extern CInterfacesAction* gInterfacesAction;
- extern CProxyControl* gProxyControl;
-
- // ---------------------------------------------------------------------------------
- // • CDNSAction()
- // ---------------------------------------------------------------------------------
- CDNSAction::CDNSAction()
- {
- // other initialization
- mReceiveUDPThread = nil;
- mSendUDPThread = nil;
- mUDPEndpoint = nil;
- mResponseArray = nil;
- mIsServing = false;
- mWaitingToStop = false;
- mWaitingToRestart = false;
- mDNSRetryCount = kDNSRetryCount;
- mIdleDelay = kDNSIdleDefault;
-
- mDNRProxyEndpoint = nil;
- mDNRProxyRxThread = nil;
- mDNRSourceAddr = 0;
- mDNRSourcePort = 0;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • ~CDNSAction
- // ---------------------------------------------------------------------------------
- CDNSAction::~CDNSAction()
- {
- StopServing();
- if (mResponseArray) delete mResponseArray;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • Terminate
- // ---------------------------------------------------------------------------------
- void
- CDNSAction::Terminate(Boolean inCanWait)
- {
- // Release thread objects we created
- if (mReceiveUDPThread) mReceiveUDPThread->Abort();
- if (mSendUDPThread) mSendUDPThread->Abort();
- if (mDNRProxyRxThread) mDNRProxyRxThread->Abort();
-
- if (inCanWait) {
- // Wait for threads to abort normally
- UInt8 retryLimit = 24;
- while ( (mReceiveUDPThread != nil) ||
- (mSendUDPThread != nil) ||
- (mDNRProxyRxThread != nil) ) {
- LThread::Yield();
- retryLimit -= 1;
- if (retryLimit == 0) break;
- }
- }
-
- // if threads didn't complete, cleanup as best we can
- if (mReceiveUDPThread) {
- mReceiveUDPThread->DeleteThread();
- mReceiveUDPThread = nil;
- }
- if (mSendUDPThread) {
- mSendUDPThread->DeleteThread();
- mSendUDPThread = nil;
- }
- if (mDNRProxyRxThread) {
- mDNRProxyRxThread->DeleteThread();
- mDNRProxyRxThread = nil;
- }
-
- // Release the UDP Endpoint we created
- if (mUDPEndpoint) {
- // no longer want notification of endpoint events
- mUDPEndpoint->RemoveListener(this);
- delete mUDPEndpoint;
- mUDPEndpoint = nil;
- }
- if (mDNRProxyEndpoint) {
- // no longer want notification of endpoint events
- //mDNRProxyEndpoint->RemoveListener(this);
- delete mDNRProxyEndpoint;
- mDNRProxyEndpoint = nil;
- }
- }
-
-
- // ---------------------------------------------------------------------------------
- // • StartServing
- // ---------------------------------------------------------------------------------
- Boolean
- CDNSAction::StartServing()
- {
- OSErr err = noErr;
- Boolean result = false;
-
- if (!mIsServing && !mWaitingToRestart) {
- mWaitingToRestart = false;
- try {
- // Create a tcp endpoint to force the InetConfigurator to fire
- // (blocks until TCP/IP is ready)
- err = gProxyControl->AsyncOpenAndClose();
- if (err != noErr) {
- // Could not initialize OT. Wait and try again.
- gLogAction->LogText("\p\rCDNSAction::StartServing() unexpected result initializing OT: ", err);
- if (mDNSRetryCount > 0) {
- mDNSRetryCount -= 1;
- mIdleDelay = kDNSIdleRestart; // set idle time for restart
- OTGetTimeStamp(&mLastStamp);
- mWaitingToRestart = true;
- //this->StartIdling();
- this->StartRepeating();
- }
- else {
- this->StopRepeating();
- mDNSRetryCount = kDNSRetryCount;
- }
- ThrowIfNil_(nil);
- }
-
- if (!mResponseArray) {
- mResponseArray = new LArray(sizeof(dns_request_t));
- ThrowIfNil_(mResponseArray);
- //mResponseArray->SetComparator(LLongComparator::GetComparator());
- }
-
- // Create a UDP endpoint
- if (!mUDPEndpoint) {
- mUDPEndpoint = new CTurboUDPEndpoint(kUDPName);
- ThrowIfNil_(mUDPEndpoint);
- // Register to receive other event notifications
- mUDPEndpoint->AddListener(this);
- }
-
- // Create thread objects for receive and transmit
- if (!mReceiveUDPThread) {
- mReceiveUDPThread = new CReceiveUDPThread(
- (CObjectMaster*) this,
- (CTurboUDPEndpoint*) mUDPEndpoint);
- ThrowIfNil_(mReceiveUDPThread);
- // Bind to DNS server port
- LInternetAddress address(0, kDNSServerPort);
- mReceiveUDPThread->Bind(address);
- mReceiveUDPThread->Resume();
- }
- if (!mSendUDPThread) {
- mSendUDPThread = new CSendUDPThread(
- (CObjectMaster*) this,
- (CTurboUDPEndpoint*) mUDPEndpoint); // coerce to re-use code
- ThrowIfNil_(mSendUDPThread);
- mSendUDPThread->Resume();
- }
- // Create DNR Proxy endpoint
- if (!mDNRProxyEndpoint) {
- mDNRProxyEndpoint = new CTurboUDPEndpoint(kUDPName);
- ThrowIfNil_(mDNRProxyEndpoint);
- // Register to receive other event notifications
- //mUDPEndpoint->AddListener(this);
- }
-
- // Create receive thread object for DNR Proxy
- if (!mDNRProxyRxThread) {
- mDNRProxyRxThread = new CReceiveUDPThread(
- (CObjectMaster*) this,
- (CTurboUDPEndpoint*) mDNRProxyEndpoint);
- ThrowIfNil_(mDNRProxyRxThread);
- // Bind to any local port
- mDNRProxyRxThread->Resume();
- }
-
- // record server start time
- if (!mIsServing) {
- ::OTGetTimeStamp(&mLastStamp);
- }
-
- // Start idling to check for time outs
- //this->StartIdling();
- this->StartRepeating();
- mIsServing = true;
- gLogAction->LogText("\p\rDNS Action: Start DNS Deferral server");
- result = true;
- }
- catch (...) {
- gLogAction->LogText("\p\rUnexpected result while starting DNS Deferral");
- }
- }
- return result;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • StopServing
- // ---------------------------------------------------------------------------------
- Boolean
- CDNSAction::StopServing(Boolean inCanWait)
- {
- if (mIsServing) {
- mIsServing = false;
- gLogAction->LogText("\p\rDNS Action: Stop DNS Deferral Server");
- }
- // stop any pending restart
- mWaitingToRestart = false;
- // stop any pending shutdown
- mWaitingToStop = false;
- //this->StopIdling();
- this->StopRepeating();
- // clean up
- Terminate(inCanWait);
- mDNSRetryCount = kDNSRetryCount; // reinitialize retry counter
- return true;
- }
-
-
- // ---------------------------------------------------------------------------------
- // • StopDeferral
- // ---------------------------------------------------------------------------------
- // This method is called when PPP comes back on-line to indicate we should
- // stop deferring clients. We do this by telling them to lookup the
- // original name they requested.
- void
- CDNSAction::StopDeferral()
- {
- if (mIsServing && !mWaitingToStop) {
- mWaitingToStop = true;
- ::OTGetTimeStamp(&mStopStamp);
- gLogAction->LogText("\p\rDNS Action: Stop DNS Deferral");
- }
- }
-
-
- // ---------------------------------------------------------------------------------
- // • ResumeDeferral
- // ---------------------------------------------------------------------------------
- // This method is called when PPP comes back on-line to indicate we should
- // stop deferring clients. We do this by telling them to lookup the
- // original name they requested.
- void
- CDNSAction::ResumeDeferral()
- {
- if (mIsServing && mWaitingToStop) {
- mWaitingToStop = false;
- gLogAction->LogText("\p\rDNS Action: Resume DNS Deferral");
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • ObjectThreadDied
- // ---------------------------------------------------------------------------
- // A threaded operation has completed.
- void
- CDNSAction::ObjectThreadDied(LThread *inThread) {
-
- // Receive Thread completed?
- if (inThread == mReceiveUDPThread) {
- // get result
- long result = *((long*)inThread->GetResult());
- // indicate thread no longer exists
- mReceiveUDPThread = nil;
- LastComplete();
- // handle results
- switch (result) {
- case 0: // no error
- case Abort_Error: // operation aborted
- result = 0;
- break;
- default:
- gLogAction->LogText("\p\r### DNSAction CReceiveUDPThread unexpected event code: ", result);
- break;
- } // end switch
-
- if (result != 0) {
- // Thread died due to Endpoint event, try to recover
- if (mIsServing) {
- StopServing(true);
- mIdleDelay = kDNSIdleRestart; // set idle time for restart
- OTGetTimeStamp(&mLastStamp);
- mWaitingToRestart = true;
- //this->StartIdling();
- this->StartRepeating();
- //StartServing();
- }
- }
- }
-
- // Transmit Thread completed?
- else if (inThread == mSendUDPThread) {
- // get result
- long result = *((long*)inThread->GetResult());
- // indicate thread no longer exists
- mSendUDPThread = nil;
- LastComplete();
- // handle results
- switch (result) {
- case 0: // no error
- case Abort_Error: // operation aborted
- result = 0;
- break;
- default:
- gLogAction->LogText("\p\r### DNSAction CSendUDPThread unexpected event code: ", result);
- break;
- } // end switch
-
- if (result != 0) {
- // Thread died due to Endpoint event, try to recover
- if (mIsServing) {
- StopServing(true);
- mIdleDelay = kDNSIdleRestart; // set idle time for restart
- OTGetTimeStamp(&mLastStamp);
- mWaitingToRestart = true;
- //this->StartIdling();
- this->StartRepeating();
- //StartServing();
- }
- }
- }
- // DNR Proxy Receive Thread completed?
- else if (inThread == mDNRProxyRxThread) {
- // get result
- long result = *((long*)inThread->GetResult());
- // indicate thread no longer exists
- mDNRProxyRxThread = nil;
- LastComplete();
- // handle results
- switch (result) {
- case 0: // no error
- case Abort_Error: // operation aborted
- result = 0;
- break;
- default:
- gLogAction->LogText("\p\r### DNSAction DNRPRoxyRxThread unexpected event code: ", result);
- break;
- } // end switch
-
- if (result != 0) {
- // Thread died due to Endpoint event, try to recover
- if (mIsServing) {
- StopServing(true);
- mIdleDelay = kDNSIdleRestart; // set idle time for restart
- OTGetTimeStamp(&mLastStamp);
- mWaitingToRestart = true;
- //this->StartIdling();
- this->StartRepeating();
- //StartServing();
- }
- }
- }
- }
-
-
- // ---------------------------------------------------------------------------------
- // • LastComplete
- // ---------------------------------------------------------------------------------
- // Release our UDP endpoint only after all threads have safely completed
- void
- CDNSAction::LastComplete()
- {
- if ((mReceiveUDPThread == nil) &&
- (mSendUDPThread == nil)) {
- // Release the UDP Endpoint we created
- if (mUDPEndpoint) {
- mUDPEndpoint->RemoveListener(this);
- delete mUDPEndpoint;
- mUDPEndpoint = nil;
- }
- }
- if ((mDNRProxyRxThread == nil)) {
- // Release the Endpoint we created
- if (mDNRProxyEndpoint) {
- //mDNRProxyEndpoint->RemoveListener(this);
- delete mDNRProxyEndpoint;
- mDNRProxyEndpoint = nil;
- }
- }
- }
-
-
- // ---------------------------------------------------------------------------------
- // • ListenToMessage
- // ---------------------------------------------------------------------------------
- // Listen for other notifications from endpoint
- // BroadcastMessage(nextMessage->GetMessageType(), nextMessage);
- void
- CDNSAction::ListenToMessage(
- MessageT inEventCode,
- void *ioParam )
- {
- LNetMessage* inMessage = (LNetMessage*)ioParam;
-
- switch ( inEventCode ) {
- case kOTProviderWillClose:
- case kOTProviderIsClosed:
- gLogAction->LogText("\p\rDNSAction: OT Provider has closed.");
- break;
- case msg_BroadcasterDied:
- // unknown
- case 0x04:
- case 0x40:
- //gLogAction->LogText("\p\rDNSAction unknown async message type: ", inEventCode);
- // try to recvoer
- if (mIsServing) {
- //StopServing(true);
- UInt32 outRemoteAddress;
- UInt16 outRemotePort;
- SInt32 outError;
- //Str31 str;
- outRemoteAddress = 0;
- outRemotePort = 0;
- outError = 0;
- if (mUDPEndpoint) {
- mUDPEndpoint->ReceiveError(outRemoteAddress, outRemotePort, outError);
- //gLogAction->LogText("\p\rDNSAction ReceiveError from ");
- //IP_NumToStr(outRemoteAddress, str);
- //gLogAction->LogText(str);
- //gLogAction->LogText("\p:");
- //::NumToString(outRemotePort, str);
- //gLogAction->LogText(str);
- //gLogAction->LogText("\p result: ", outError);
- } else {
- StartServing();
- }
- }
- break;
- default:
- gLogAction->LogText("\p\rDNSAction unexpected async message type: ", inEventCode);
- gLogAction->LogText("\p\r Result code: ", inMessage->GetResultCode());
- // try to recvoer
- if (mIsServing) {
- StopServing(true);
- mIdleDelay = kDNSIdleRestart; // set idle time for restart
- OTGetTimeStamp(&mLastStamp);
- mWaitingToRestart = true;
- //this->StartIdling();
- this->StartRepeating();
- //StartServing();
- }
- }
- }
-
- #pragma mark --- Handle Requests ---
-
- // ---------------------------------------------------------------------------
- // • Receive Data
- // ---------------------------------------------------------------------------
- // Handle data that arrived from the network.
- void
- CDNSAction::ReceiveData(LDataArrived* inMessage)
- {
- dns_request_t dnsRequest;
- LInternetAddress* inRemoteAddress;
- LEndpoint* theEndpoint;
-
- // test which endpoint message is from
- theEndpoint = inMessage->GetEndpoint();
- if (theEndpoint == mDNRProxyEndpoint) {
- ReceiveDNRProxy(inMessage);
- return;
- }
-
- // initialize dnsRequest structure
- OTMemzero(&dnsRequest, sizeof(dns_request_t));
-
- // setup access to message data and addresses
- dnsRequest.md.data = (UInt8*)inMessage->GetDataBuffer();
- dnsRequest.md.size = inMessage->GetDataSize();
- dnsRequest.md.offset = 0;
- // remote address
- inRemoteAddress = inMessage->GetRemoteAddress();
- dnsRequest.remoteAddr = inRemoteAddress->GetIPAddress();
- dnsRequest.remotePort = inRemoteAddress->GetHostPort();
- // receive time
- OTGetTimeStamp(&dnsRequest.timeStamp);
-
- // Process Request
- ProcessRequest(&dnsRequest);
- }
-
-
- // ---------------------------------------------------------------------------
- // • ProcessRequest
- // ---------------------------------------------------------------------------
- // Process DNS request
- void
- CDNSAction::ProcessRequest(dns_request_t* inRequest)
- {
- dns_header_t* dnsHeader;
- msg_descriptor_t* md;
- UInt8* dp;
- UInt16 qType, qClass;
- Str255 qName;
- LStr255 text;
- Str31 str;
- Boolean isTypePTR = false;
- OTResult err;
-
- // setup to access header fields
- md = &inRequest->md;
- dp = (UInt8*)md->data;
- dnsHeader = (dns_header_t*)md->data;
-
- do {
- // ignore responses
- if (dnsHeader->queryParameter & kQueryMaskQR) break;
- // make sure there is a question
- if (dnsHeader->QDCount == 0) break;
- // skip header
- md->offset = 12;
- // get the query name
- GetDName(md, qName);
- // get query type and class
- ::BlockMove(&dp[md->offset], &qType, 2);
- ::BlockMove(&dp[md->offset+2], &qClass, 2);
-
- // if query is a simple name lookup
- if ((qClass == kQClassIN) && (qType == kQTypeA)) {
- if (false) {
- // show user
- text = "\p\rDNS query from ";
- IP_NumToStr(inRequest->remoteAddr, str);
- text += str;
- if (inRequest->remotePort != 0) {
- NumToString(inRequest->remotePort, str);
- text += "\p:";
- text += str;
- }
- gLogAction->LogText(text);
- text = "\p\r qName=";
- text += qName;
- gLogAction->LogText(text);
- gLogAction->Update();
- }
- // if not deferring and a real name
- if (mWaitingToStop && !IsFakeDialingName(qName)) {
- // forward request to real DNS
- mDNRSourceAddr = inRequest->remoteAddr;
- mDNRSourcePort = inRequest->remotePort;
- ForwardToDNS(md->data, md->size);
- }
- else {
- // save in array for future processing
- // copy message content
- ::BlockMove(md->data, inRequest->buf, md->size);
- // add to array
- mResponseArray->AddItem(inRequest, sizeof(dns_request_t));
- mIdleDelay = kDNSIdleData;
- /*
- // test fake string
- text = "\p\r fake dialing name: ";
- Str255 outStr;
- text += GetFakeDialingName(qName, outStr);
- gLogAction->LogText(text);
-
- text = "\p\r real dialing name: ";
- text += GetRealDialingName(outStr, qName);
- gLogAction->LogText(text);
- gLogAction->Update();
- */
- }
- }
- else if ((qClass == kQClassIN) && (qType == kQTypePTR)) {
- isTypePTR = true;
- }
- } while (false);
-
- // Since we received a DNS request, PPP must not be connected.
- // Tell PPP to connect if necessary.
- if (gResInfo->IsMonitoringPPP() && !isTypePTR) {
- UInt32 linkState;
- linkState = gConnectionData->GetDataLinkState();
- if ((linkState == kLinkStateIdle) || (linkState == kLinkStateNone)) {
- err = gResInfo->ConnectPPP(nil);
- if (err != kOTNoError) gLogAction->LogText("\p\rCDNSAction - unexpected PPP connect result: ", err);
- }
- }
- }
-
-
- // ---------------------------------------------------------------------------
- // • SpendTime
- // ---------------------------------------------------------------------------
- // Periodical function to test if we have a request waiting
- // or other pending action.
- void
- CDNSAction::SpendTime(const EventRecord &inMacEvent)
- {
- #pragma unused (inMacEvent)
- UInt32 deltaTime;
- UInt32 requestAge;
- ArrayIndexT count, index;
- Boolean result;
-
- // do every "mIdleDelay" milliseconds
- deltaTime = OTElapsedMilliseconds(&mLastStamp);
- if (deltaTime > mIdleDelay) {
- OTGetTimeStamp(&mLastStamp);
- do {
- // check if pending restart
- if (mWaitingToRestart) {
- mWaitingToRestart = false;
- StartServing();
- break;
- }
- // check if waiting to stop
- // if (mWaitingToStop) {
- // deltaTime = OTElapsedMilliseconds(&mStopStamp);
- // if (deltaTime > 30000) { // 30 seconds
- // StopServing();
- // break;
- // }
- // }
- // check response array
- if (!mResponseArray) {
- StopServing();
- break;
- }
- count = mResponseArray->GetCount();
- if (count == 0) mIdleDelay = kDNSIdleDefault; // no responses waiting
- for (index=1; index<=count; index++) {
- dns_request_t dnsRequest;
- if (!mResponseArray->FetchItemAt(index, &dnsRequest)) continue;
- // found a request entry from array
- // set md for saved buffer
- dnsRequest.md.data = dnsRequest.buf;
- requestAge = OTElapsedMilliseconds(&dnsRequest.timeStamp);
- // if request is older than 1.5 seconds, try to send it
- if (requestAge >= 1500) {
- result = SendResponse(&dnsRequest);
- if (result) {
- // response was sent, remove from array
- mResponseArray->RemoveItemsAt(1, index);
- index -= 1;
- }
- // allow SendThread to run before trying next in array
- LThread::Yield();
- }
- }
- } while (false);
- } // end if (deltaTime > mIdleDelay)
- }
-
-
- // ---------------------------------------------------------------------------
- // • SendResponse
- // ---------------------------------------------------------------------------
- // Send DNS Response
- // Try to send response, return false if SendThread is busy
- Boolean
- CDNSAction::SendResponse(dns_request_t* inRequest)
- {
- msg_descriptor_t md;
- long index=0;
- UInt16 param;
- Str255 qName;
- Str255 outName;
- Boolean result;
-
- do {
- // if thread is ready, send it
- result = mSendUDPThread->IsReady();
- if (!result) break;
- // build response
- // we start with the original query
- // set parameter to indicate a response
- param = kQueryMaskQR;
- ::BlockMove(¶m, &inRequest->md.data[2], 2);
- // indicate 1 answer
- param = 1;
- ::BlockMove(¶m, &inRequest->md.data[6], 2);
- // we leave the question as received
- // get query name
- inRequest->md.offset = 12; // start of question
- result = GetDName(&inRequest->md, qName);
- if (!result) {
- result = 1; // delete entry
- break; // get out
- }
- inRequest->md.offset += 4; // skip the qType and qClass
-
- // now we're ready to start loading our answer
- // set md to the end of the query we received
- md.data = inRequest->md.data;
- md.offset = inRequest->md.offset;
- md.size = kMaxResponseLen;
-
- // repeat the query name as the resource owner
- PutDName(&md, qName);
-
- // check if we are connected yet and determine the CName response
- UInt32 linkState;
- linkState = gConnectionData->GetDataLinkState();
- if (linkState == kLinkStateConnected) {
- // yes, restore real domain name
- GetRealDialingName(qName, outName);
- } else {
- // no, use FAKE dialing name
- index = GetFakeDialingName(qName, outName);
- // stop deferring after two minutes (80 * 1.5sec)
- if (index > 80) break;
- }
- // continue filling in answer Resource Record
- dns_record_t* rr;
- rr = (dns_record_t*)&md.data[md.offset];
- rr->rdType = kQTypeCNAME;
- rr->rdClass = kQClassIN;
- rr->rdTTL = 1;
- // length = +1 for initial length and +1 for termination 0
- rr->rdLength = outName[0] + 2;
- md.offset += 10;
- // write our CName response
- PutDName(&md, outName);
- // set message length
- md.size = md.offset;
- // where to?
- LInternetAddress address(inRequest->remoteAddr, inRequest->remotePort);
- // send it
- result = mSendUDPThread->SendUData(address, md.data, md.size);
- // tell user what we did
- //LogDNSResponse(inResponse);
- } while (false);
-
- return result;
- }
-
-
- // ---------------------------------------------------------------------------
- // • ForwardToDNS
- // ---------------------------------------------------------------------------
- // Forward query to real DNS server
- OTResult
- CDNSAction::ForwardToDNS(UInt8* inData, UInt32 inDataSize)
- {
- TUnitData data;
- Str31 addrStr;
- LStr255 text;
- UInt32 addr;
- LInternetAddress remoteHost;
- EndpointRef ep;
- OTResult result=kOTNoError;
-
- do {
- gInterfacesAction->GetDNSAddress(addrStr);
- addr = IP_StrToInt(addrStr);
- if ((addr == mDNRSourceAddr) || (addr == 0)) {
- gLogAction->LogText("\p\r no DNS Server available");
- break;
- }
- if (mDNRProxyEndpoint != 0) {
- if (false) {
- // show user
- text = "\p\r Forwarding to DNS Server: ";
- text += addrStr;
- gLogAction->LogText(text);
- }
- // setup destination
- remoteHost.SetIPAddress( addr );
- remoteHost.SetHostPort( kDNSServerPort );
- remoteHost.MakeOTIPAddress(data.addr);
- // setup UDP data
- data.opt.maxlen = 0;
- data.opt.len = 0;
- data.opt.buf = nil;
- data.udata.maxlen = data.udata.len = inDataSize;
- data.udata.buf = (unsigned char*)inData;
- // get OT endpoint ref
- ep = mDNRProxyEndpoint->GetEndpointRef();
- // set synchronous
- ::OTSetSynchronous(ep);
- ::OTSetBlocking(ep);
- result = ::OTSndUData(ep, &data);
- while (result == kOTLookErr) {
- //Clear Error
- ::OTRcvUDErr(ep, NULL);
- //Try again
- result = ::OTSndUData(ep, &data);
- }
- ::DisposePtr((Ptr)data.addr.buf);
- // restore to asynchronous
- OTSetNonBlocking(ep);
- ::OTSetAsynchronous(ep);
- }
- } while (false);
- return result;
- }
-
-
- // ---------------------------------------------------------------------------
- // • ReceiveDNRProxy
- // ---------------------------------------------------------------------------
- // Handle data that arrived from DNS
- void
- CDNSAction::ReceiveDNRProxy(LDataArrived* inMessage)
- {
- UInt8* dataBuf;
- UInt32 dataSize;
-
- // setup access to message data and addresses
- dataBuf = (UInt8*)inMessage->GetDataBuffer();
- dataSize = inMessage->GetDataSize();
- ForwardFromDNS(dataBuf, dataSize);
- }
-
-
- // ---------------------------------------------------------------------------
- // • ForwardFromDNS
- // ---------------------------------------------------------------------------
- // Forward response from real DNS server
- OTResult
- CDNSAction::ForwardFromDNS(UInt8* inData, UInt32 inDataSize)
- {
- TUnitData data;
- LInternetAddress remoteHost;
- EndpointRef ep;
- OTResult result;
-
- if (mUDPEndpoint != 0) {
- remoteHost.SetIPAddress( mDNRSourceAddr );
- remoteHost.SetHostPort( mDNRSourcePort );
-
- remoteHost.MakeOTIPAddress(data.addr);
- data.opt.maxlen = 0;
- data.opt.len = 0;
- data.opt.buf = nil;
- data.udata.maxlen = data.udata.len = inDataSize;
- data.udata.buf = (unsigned char*)inData;
-
- // get OT endpoint ref
- ep = mUDPEndpoint->GetEndpointRef();
- // set synchronous
- ::OTSetSynchronous(ep);
- ::OTSetBlocking(ep);
- result = ::OTSndUData(ep, &data);
- while (result == kOTLookErr) {
- //Clear Error
- ::OTRcvUDErr(ep, NULL);
- //Try again
- result = ::OTSndUData(ep, &data);
- }
- ::DisposePtr((Ptr)data.addr.buf);
- // restore to asynchronous
- ::OTSetNonBlocking(ep);
- ::OTSetAsynchronous(ep);
- }
- return result;
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetDName
- // ---------------------------------------------------------------------------
- // Convert a sequence of labels in Name Server format to a name string
- // Return false if name exceeds maximum length (255)
- // or contains an invalid pointer.
- Boolean
- CDNSAction::GetDName(msg_descriptor_t* md, Str255 outStr)
- {
- LStr255 name;
- Str255 label;
- UInt8 len;
- UInt16 offset, pointer, oldPointer, nameLength;
- UInt16* dp;
- Boolean isPointer;
-
- name = "\p"; // initialize name
- nameLength = 0;
- offset = md->offset;
- isPointer = false;
-
- len = md->data[offset];
- // copy each label until end of name indicated by 0
- while (len) {
- // is it a pointer?
- if (len >= 64) {
- // yes, get pointer
- if (!isPointer) {
- dp = (UInt16*)&md->data[offset]; // cast to 16-bit quantity
- offset += 2; // advance current offset past pointer
- } else {
- dp = (UInt16*)&md->data[pointer]; // cast to 16-bit quantity
- }
- oldPointer = pointer;
- pointer = dp[0] & 0x3FFF; // get new pointer
- // pointers must refer to a prior occurance of the same name
- // reject garbage pointers and pointer loops (defensive)
- if (!isPointer && (pointer >= offset)) return false;
- if (isPointer && (pointer >= oldPointer)) return false;
- isPointer = true;
- } else {
- // no, copy label
- if (!isPointer) {
- LString::CopyPStr(&md->data[offset], label, 64);
- offset += len + 1; // advance offset past label
- } else {
- LString::CopyPStr(&md->data[pointer], label, 64);
- pointer += len + 1; // advance pointer past label
- }
- // add label to name
- name += label;
- name += "\p."; // append a dot
- // check for valid length (defensive)
- nameLength += len + 1;
- if (nameLength > 255) return false;
- }
- // prepare to get next label
- if (!isPointer) len = md->data[offset];
- else len = md->data[pointer];
- }
- // if not a pointer, skip terminating zero
- if (!isPointer) offset += 1;
- // update ioOffset
- md->offset = offset;
-
- // remove final dot from end of name
- len = name.Length();
- if (len != 0) name.Remove(len, 1);
- // return the resulting name
- LString::CopyPStr(name, outStr, 255);
- return true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • PutDName
- // ---------------------------------------------------------------------------
- // Write a domain name in Name Server format
- // as a sequence of labels.
- // Return false if name won't fit in message.
- Boolean
- CDNSAction::PutDName(msg_descriptor_t* md, ConstStr255Param inStr)
- {
- LStr255 name, label;
- UInt8 start, pos;
- UInt16 offset;
- UInt8* inMessage;
-
- inMessage = md->data;
- name = inStr;
- offset = md->offset;
- // copy each segment separated by '.' as a PString
- start = 1;
- pos = name.Find('.', start);
- while (pos != 0) {
- label.Assign(name, start, pos-start);
- if ((label.Length() + offset) >= md->size) return false;
- LString::CopyPStr(label, &inMessage[offset]);
- offset += pos-start + 1;
- start = pos + 1;
- pos = name.Find('.', start);
- }
- // get last segment
- label.Assign(name, start);
- if ((label.Length() + offset) >= (md->size-1)) return false;
- LString::CopyPStr(label, &inMessage[offset]);
- offset += label[0] + 1; // adjust offset to include length
- // mark the end if necessary
- if (label[0] != 0) {
- inMessage[offset] = 0;
- offset += 1;
- }
-
- // set new offset
- md->offset = offset;
- return true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • IsFakeDialingName
- // ---------------------------------------------------------------------------
- // Test if supplied string is a fake CName used for dialing.
- // If so, return offset to first byte of dialing prefix, otherwise zero.
- UInt8
- CDNSAction::IsFakeDialingName(ConstStr255Param inStr)
- {
- LStr255 str;
- UInt8 pos;
-
- str = inStr;
- pos = str.Find(kDialingPrefixStr);
- return pos;
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetFakeDialingName
- // ---------------------------------------------------------------------------
- // Determine FAKE dialing name from REAL domain name, or previous FAKE
- // dialing name of the form <real-name><kDialingPrefixStr>nnn<kDialingSufixStr>,
- // Return nnn, the fake dialing name index
- long
- CDNSAction::GetFakeDialingName(ConstStr255Param inStr, Str255 outStr)
- {
- LStr255 str;
- UInt8 pos;
- long index = 0;
-
- pos = IsFakeDialingName(inStr);
- if (pos == 0) {
- // convert to fake name by adding dialing name
- str = inStr;
- str += kDialingPrefixStr;
- str += "\p1";
- index = 1;
- str += kDialingSufixStr;
- }
- else {
- Str31 s;
- // get fake string index
- pos += kDialingPrefixStr[0]; // skip dialing prefix
- str = inStr;
- str.Assign(str, 1, pos-1); // remember start of dialing name
- index = 0; // convert dialing index to numvber
- while (IsDigit(inStr[pos])) {
- index *= 10;
- index += inStr[pos] - '0';
- pos += 1;
- }
- index += 1; // increment index
- NumToString(index, s); // convert to string
- str += s; // append to start of dialing name
- str += kDialingSufixStr; // append dialing sufix
- }
- LString::CopyPStr(str, outStr);
- return index;
- }
-
-
- // ---------------------------------------------------------------------------
- // • GetRealDialingName
- // ---------------------------------------------------------------------------
- // Determine REAL dialing name from possible FAKE dialing name of the form
- // <real-name><kDialingPrefixStr>nnn<kDialingSufixStr>
- StringPtr
- CDNSAction::GetRealDialingName(ConstStr255Param inStr, Str255 outStr)
- {
- LStr255 str;
- UInt8 pos;
-
- pos = IsFakeDialingName(inStr);
- if (pos != 0) {
- // convert to REAL name by removing dialing name
- str = inStr;
- str.Assign(str, 1, pos-1);
- }
- else {
- str = inStr;
- }
- return LString::CopyPStr(str, outStr);
- }
-